﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework;

namespace mbhxnaengine.Code.Utilities
{
    // Singleton class used for displaying debug information to the screen.  This
    // is helpful for analyzing things in fullscreen mode, as well as looking at
    // data that changes frequenty.
    //
    class DebugMessageDisplay
    {
        // The static instance of this class, making this a singleton.
        //
        static private DebugMessageDisplay mInstance = null;

        // This string will store our messages that are only shown for one frame
        //
        private String mDynamicMsgs;

        // This array will store the constant strings
        //
        private String[] mConstantMsgs;

        // This is how many constant strings we are going to store
        //
        private int mMaxConstMsgs = 10;

        // This will keep track of the current message number
        //
        private int mCurMsgNum = 0;

        // The font object we use for rendering.
        //
        private SpriteFont mFont;

        // A handle to our graphics device.  This gets passed in on initialization
        // and is used to help place the text at different ends of the screen.
        //
        private GraphicsDevice mGraphics;

        // Offset for keeping the debug display within the safe zone of a TV
        //
        private int safeZoneOffsetX = 40;
        private int safeZoneOffsetY = 20;

        // Renders the dynamic messages.
        //
        private void RenderDynamicMsgs(SpriteBatch spriteBatch)
        {
            // The dynamic message is just stored as a long single string, so we only need one
            // draw call (as well as a copy for the drop shadow).
            spriteBatch.DrawString(mFont, mDynamicMsgs, new Vector2(1 + safeZoneOffsetX, 1 + safeZoneOffsetY), Color.Black);
            spriteBatch.DrawString(mFont, mDynamicMsgs, new Vector2(0 + safeZoneOffsetX, 0 + safeZoneOffsetY), Color.White);
        }

        // Renders the constant messages.
        //
        private void RenderConstMsgs(SpriteBatch spriteBatch)
        {
            // Determine the starting alpha value
            float alphaCur = 1.0f;
            float alphaDec = 1.0f / mMaxConstMsgs;

            // Loop through all the messages
            for (int i = 0; i < mMaxConstMsgs; i++)
            {
                if (mConstantMsgs[i] != "")
                {
                    // Get the bottom of the window.
                    int bottom = mGraphics.Viewport.Height;

                    // The font is anchored at the top so we need to move it up by it's height in order
                    // to get it on screen.  We add an extra pixel so that the drop shadow fits on screen
                    // too.
                    bottom -= 15 + 1;

                    // We want each entry in the array to appear above the previous entry.
                    bottom -= i * 15;

                    // Draw the message at the bottom of the screen.
                    spriteBatch.DrawString(mFont, mConstantMsgs[i], new Vector2(1 + safeZoneOffsetX, bottom + 1 - safeZoneOffsetY), new Color(Color.Black, alphaCur));
                    spriteBatch.DrawString(mFont, mConstantMsgs[i], new Vector2(0 + safeZoneOffsetX, bottom - safeZoneOffsetY), new Color(Color.White, alphaCur));

                    // Make it so the next message is a little less visable
                    alphaCur -= alphaDec;
                }
            }
        }

        // Initializes the class.
        //
        public void Initialize(ContentManager content, GraphicsDevice graphics)
        {
            // Keep a handle to the graphics device for rendering to edges of screen.
            mGraphics = graphics;

            // Create the font
            mFont = content.Load<SpriteFont>("Fonts\\GameFont");

            // Start with an empty string
            mDynamicMsgs = "Debug Information:";

            // Allocate our constant string
            mConstantMsgs = new String[mMaxConstMsgs];

            // Clear all the messages.
            for (int i = 0; i < mMaxConstMsgs; i++)
            {
                mConstantMsgs[i] = "";
            }
        }

        // Renders all the current debug messages.
        //
        public void Render(SpriteBatch spriteBatch)
        {
            RenderDynamicMsgs(spriteBatch);

            // Draw the constant messages
            RenderConstMsgs(spriteBatch);
        }

        // Clears all the dyanmic messages.  Should be called at the end of every update.
        // This is so that if there renderer is not called at the same frequency as the 
        // update, we won't get duplicate messages.
        //
        public void ClearDynamicMessages()
        {
            // When we finish rendering we want to clear the dynamic messages
            mDynamicMsgs = "Debug Information:";
        }

        // Interface for adding dynamic messages to the system.  These get cleared every frame
        // so they need to be re-added every frame.  This is perfect for data that changes constantly,
        // such as a frame rate counter.
        //
        public void AddDynamicMessage(String newMsg)
        {
            // Add the new message to the current one
            mDynamicMsgs += "\n" + newMsg;
        }

        // Interface for adding constant messages to the system.  These never get cleared, they are
        // just concatinated to the end of the list.  This is pefect for data that you want to keep a
        // record of events on, such as objects being added and removed from the game.
        //
        public void AddConstantMessage(String newMsg)
        {
            // Start at the last message and copy in the next one
            for (int i = mMaxConstMsgs - 1; i > 0; i--)
            {
                // Copy the message below into the message above
                mConstantMsgs[i] = mConstantMsgs[i - 1];
            }

            // And finally copy in the new message
            mCurMsgNum++;
            mConstantMsgs[0] = mCurMsgNum + ": " + newMsg;
        }

        // Accessor to the pInstance property.
        //
        public static DebugMessageDisplay pInstance
        {
            get
            {
                // If this is the first time this is called, instantiate our
                // static instance of the class.
                if (mInstance == null)
                {
                    mInstance = new DebugMessageDisplay();
                }

                // Either way, at this point we should have an instantiated version
                // if the class.
                return mInstance;
            }
        }
    }
}
